﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufBase.h"
#include "GnufImpl.h"
#include "GnufInfo.h"

namespace gnuf {
    
    class MainTitleBar;
    class MainToolbar;
/*
    + - - - - - - - - - - - - - - - - - - - - - - - - - - - +
    . Window Title Bar                                _ □ x .
    +---------------+---------------------------------------+
    |               | Main Title Bar                        |
    |               | (Secondary)                           |
    |               +---------------------------------------+
    | Module Bar    |                                       |
    | (Primary)     | Main Toolbar                          |
    |               | (Tertiary)                            |
    |               |                                       |
    +---------------+- - - - - -+---------------------------+
                    .           .
                    . Module    .
                    . Dropdown  .
                    . Menu      .
                    .           .
                    + - - - - - +
    
    - Every module should have a main title bar and a main toolbar.
    - Once the active module is changed, the corresponding main title bar and
      main toolbar both will get updated according to the new active module's
      settings.
    - Module Bar is an UI component to present all or a part of the modules in
      the module manager.
    - Module Dropdown Menu is also an UI component to present the modules that
      the module bar cannot accommodate.
*/
    namespace impl { class GNUF_IMPL_CLASS(Module); }
    /// \brief Module class intends to define a module.
    class GNUF_BASE_EXPORT Module final : public gcmp::WeakReferenceable
    {
        GNUF_IMPL_USE(Module);
     public:
        explicit Module(const std::wstring & guid, const Info & info, bool asDefault);
        ~Module();
        
        /// \return Return the Guid.
        inline const std::wstring & guid() const;
        
        /// \brief Set the info.
        inline void setInfo(const Info &);
        
        /// \return Return the info that can define a caption, an icon and a tooltip.
        inline const Info & info() const;
        
        /// \return Return true if this is default module.
        inline bool isDefault() const;
        
        /// \return Return true if active.
        inline bool isActive() const;
        
        /// \brief Set the absolute file path of the original or/and modified hotkeys.
        /// \param filePathOfOriginalHotkeys: the absolute file path of the original.
        /// \param filePathOfModifiedHotkeys: the absolute file path of the modified.
        /// If not provided, the hotkeys cannot get modified.
        /// \return Return true if successful.
        inline bool setHotkeysConfig(
            const std::wstring & filePathOfOriginalHotkeys,
            const std::wstring & filePathOfModifiedHotkeys);
        
        /// \brief Set the absolute file path of the main title bar config.
        inline void setMainTitleBarConfig(const std::wstring & filePath);
        
        /// \brief Set the absolute file path of the main toolbar config.
        inline void setMainToolbarConfig(const std::wstring & filePath);

        /// \brief Set the MaintitleBar configuration xml string description.
        void setMainTitleBarConfigString(const std::wstring& str);

        /// \brief Set the mainToolbar configuration xml string description.
        void setMainToolbarBarConfigString(const std::wstring& str);

        /// \return Return the pointer to the mainTiltleBar.
        MainTitleBar * mainTitleBar();
        /// \return Return the const pointer to the mainTitleBar.
        const MainTitleBar * mainTitleBar() const;

        /// \return Return the pointer to the mainToolbar.
        MainToolbar * mainToolbar();
        /// \return Return the const pointer to the mainToolbar.
        const MainToolbar * mainToolbar() const;

    };
    
    namespace impl { class GNUF_IMPL_CLASS(ModuleManager); }
    /// \brief ModuleManager class intends to manage all the modules.
    class GNUF_BASE_EXPORT ModuleManager final
    {
        GNUF_IMPL_USE(ModuleManager);
    public:
        explicit ModuleManager();
        ~ModuleManager();
        
        /// \return Return the global instance.
        static ModuleManager * get();
        
        /// \return Return the const pointer to the default module.
        const Module * defaultModule() const;
        /// \return Return the pointer to the default module.
        Module * defaultModule();

        /// \return Return the const pointer to the visible module.
        const Module * visibleModule() const;
        /// \return Return the pointer to the visible module.
        Module * visibleModule();

        /// \return Return the const pointer to the active module.
        const Module * activeModule() const;
        /// \return Return the pointer to the active module.
        Module * activeModule();
        
        /// \brief Add a module.
        /// \param guid: The module's guid.
        /// \param info: The module's info that defines a caption, an icon and a tooltip.
        /// \param asActive: Activate this module.
        Module * addModule(const std::wstring & guid, const Info & info, bool asActive);
        
        /// \brief Remove the module.
        /// \param guid: The module's guid.
        bool removeModule(const std::wstring & guid);
        
        /// \brief Search the module by the guid.
        /// \param guid: The module's guid.
        /// \return Return the module pointer.
        const Module * moduleBy(const std::wstring & guid) const;
        Module * moduleBy(const std::wstring & guid);

        /// \brief Activate the module.
        /// \param guild: The module's guid.
        void activateModule(const std::wstring& guid);

        const Module* moduleBy(const gnuf::MainTitleBar*) const;
        Module* moduleBy(const gnuf::MainTitleBar*);

        const Module* moduleBy(const gnuf::MainToolbar*) const;
        Module* moduleBy(const gnuf::MainToolbar*);

        enum class EBehaviorType : std::uint8_t
        {
            eUnknown,
            eAlternating,
            eAttaching ///< default
        };
        /// \brief Set the behavior type. Note that this can work before the module
        /// manager is created, in other words, ModuleManager::get() returns nullptr.
        /// \see ModuleManager::behaviorType() that returns the running behavior type.
        static void setBehaviorType(ModuleManager::EBehaviorType);

        /// \return Return the running behavior type.
        ModuleManager::EBehaviorType behaviorType() const;
    };
    
}

namespace gnuf { namespace impl {

    class IModuleBar : public gcmp::WeakReferenceable
    {
    public:
        virtual void onAdded            (const Module * pNewModule) {}
        virtual void onPreRemoved       (const Module * pModule) {}
        virtual void onActivationChanged(const Module * pOldActiveModule, 
                                         const Module * pNewActiveModule) {}
    };
    
    class GNUF_IMPL_CLASS(Module) final
    {
        GNUF_IMPL_USED_BY(Module);
    public:
        GNUF_IMPL_CLASS(Module)(const std::wstring &, const Info &, bool, Module*);
        ~GNUF_IMPL_CLASS(Module)();
        
        void     hideAndThenShowSilently(Module::Impl *);
        void detachAndThenAttachSilently(Module::Impl *, Module::Impl *);

        MainTitleBar * mainTitleBar();
        MainToolbar  * mainToolbar();
        
        const MainTitleBar * mainTitleBar() const;
        const MainToolbar * mainToolbar() const;
    private:
        const std::wstring m_guid;
        Info m_info;
        const bool m_asDefault;
        gcmp::OwnerPtr< MainTitleBar > m_opMainTitleBar;
        gcmp::OwnerPtr< MainToolbar > m_opMainToolbar;
    };
    
    class GNUF_IMPL_CLASS(ModuleManager) final
    {
        GNUF_IMPL_USED_BY(ModuleManager);
    public:
        GNUF_IMPL_CLASS(ModuleManager)(ModuleManager * moduleManager);
        virtual ~GNUF_IMPL_CLASS(ModuleManager)();
        
        void setModuleBar(IModuleBar * pModuleBar) { m_wpModuleBar = pModuleBar; }
        const IModuleBar * moduleBar() const { return m_wpModuleBar.Get(); }

        Module *  addModule(const std::wstring & guid, const Info & info);
        bool   removeModule(const std::wstring & guid);
        void activateModule(const std::wstring & guid);

        const Module * activeModule() const;
        Module * activeModule();

        const Module * defaultModule() const;
        Module * defaultModule();

        const Module * visibleModule() const;
        Module * visibleModule();
        
        Module * moduleBy(const std::wstring & guid);
        const Module * moduleBy(const std::wstring & guid) const;

        // 
        // find module by maintitlebar
        const Module* moduleBy(const gnuf::MainTitleBar*) const;
        Module* moduleBy(const gnuf::MainTitleBar*);

        const Module* moduleBy(const gnuf::MainToolbar*) const;
        Module* moduleBy(const gnuf::MainToolbar*);

        // Clear the modules except for the default one.
        void clear();
   
        typedef std::list< gcmp::OwnerPtr< Module > > Modules;
        ModuleManager::Impl::Modules::const_iterator find(
            const std::wstring & guid, bool * pOK = nullptr) const;
        ModuleManager::Impl::Modules::iterator find(
            const std::wstring & guid, bool * pOK = nullptr);

        const ModuleManager::Impl::Modules & modules() const { return m_modules; }
        
        Module * addFirstModuleAsDefault(gcmp::OwnerPtr< Module > &&);
        
        class Behavior {
        protected:
            Behavior(ModuleManager::EBehaviorType type) : m_type(type) {}
            virtual ~Behavior() {}
        public:
            ModuleManager::EBehaviorType type() const { return m_type; }
            virtual void onDestructing(const ModuleManager::Impl &) = 0;
            virtual void setHasActivated(bool) = 0;
            virtual bool hasActivated() const = 0;
            virtual const Module * defaultModule() const = 0;
            virtual       Module * defaultModule() = 0;
            virtual bool onActivate(Module::Impl * pOldActive, Module::Impl * pNewActive) = 0;
            virtual const Module* onModuleBy(const std::wstring& guid) const = 0;
            virtual const Module* onModuleBy(const gnuf::MainTitleBar* pMtb) const = 0;
            virtual const Module* onModuleBy(const gnuf::MainToolbar* pMtb) const = 0;
        private:
            const ModuleManager::EBehaviorType m_type;
        };
        ModuleManager::EBehaviorType behaviorType() const;
        
    private:
        gcmp::WeakPtr< IModuleBar > m_wpModuleBar;
        ModuleManager::Impl::Modules m_modules;
        gcmp::OwnerPtr< ModuleManager::Impl::Behavior > m_opBehavior;
        
        class AlternatingBehavior : public Behavior {
        public:
            AlternatingBehavior(ModuleManager::Impl *);
            virtual ~AlternatingBehavior();
        public:
            virtual void onDestructing(const ModuleManager::Impl &) override;
            virtual void setHasActivated(bool) override
            { /* Do nothing. There must be an active module, in any case. */}
            virtual bool hasActivated() const override { return true; }
            virtual const Module * defaultModule() const override { return m_wpDefaultModule.Get(); }
            virtual       Module * defaultModule()       override { return m_wpDefaultModule.Get(); }
            virtual bool onActivate(Module::Impl * pOldActive, Module::Impl * pNewActive) override;
            virtual const Module* onModuleBy(const std::wstring& guid) const override { return nullptr; }
            virtual const Module* onModuleBy(const gnuf::MainTitleBar* pMtb) const override { return nullptr; }
            virtual const Module* onModuleBy(const gnuf::MainToolbar* pMtb) const override { return nullptr; }
        private:
            gcmp::WeakPtr< Module > m_wpDefaultModule;
        };
        
        class AttachingBehavior : public Behavior {
        public:
            AttachingBehavior(ModuleManager::Impl *);
            virtual ~AttachingBehavior();
        public:
            virtual void onDestructing(const ModuleManager::Impl &) override;
            virtual void setHasActivated(bool) override;
            virtual bool hasActivated() const override { return m_hasActivated; }
            virtual const Module * defaultModule() const override { return m_opDefaultModule.get(); }
            virtual       Module * defaultModule()       override { return m_opDefaultModule.get(); }
            virtual bool onActivate(Module::Impl * pOldActive, Module::Impl * pNewActive) override;
            virtual const Module* onModuleBy(const std::wstring& guid) const override;
            virtual const Module* onModuleBy(const gnuf::MainTitleBar* pMtb) const override;
            virtual const Module* onModuleBy(const gnuf::MainToolbar* pMtb) const override;
        private:
            ModuleManager::Impl * m_pImpl;
            bool m_hasActivated;
            gcmp::OwnerPtr< Module > m_opDefaultModule;
        };
    };
} }
